home *** CD-ROM | disk | FTP | other *** search
/ Eagles Nest BBS 8 / Eagles_Nest_Mac_Collection_Disc_8.TOAST / Developer Tools⁄Additions / MacTCPToolBx / Source Code ƒ / TCPRecvMsg.p < prev    next >
Text File  |  1989-06-01  |  9KB  |  278 lines

  1. (*
  2.     TCPRecvMsg(connectionID,waitTime,OKChar,limit) -- Return a message, where a message is
  3.         defined as either a line starting with the OKChar (if the first line does not start with this,
  4.         then the first line is returned surrounded by "•••"; this is an error indication), which should
  5.         be stripped from the message, followed by lines of text until a period on a line be itself is reached,
  6.         which final line is also stipped; or if OKChar is empty, then no initial line, but just lines of text
  7.         until a period on a line by itself, which is stripped. In addition, the following editing is performed on
  8.         the incoming text: linefeeds are removed; control-Hs and the characters immediately preceeding them
  9.         are removed; ".." at the start of lines is changed is "."; tabs are converted to spaces. If waitTime
  10.         ticks go by without reading a whole message, then return "••• time out •••". If limit characters
  11.         are input without reading a whole message, then "••• message too big •••" is appended
  12.         to the truncated message (but it's all read anyway). This routine should be able to read
  13.         SMTP, NNTP, and POP messages.
  14.  
  15.     To compile and link this file using Macintosh Programmer's Workshop,
  16.  
  17.         pascal -w TCPRecvMsg.p
  18.         link -m ENTRYPOINT -o HyperCommands -rt XFCN=7867 -sn Main=TCPRecvMsg ∂
  19.             TCPRecvMsg.p.o "{Libraries}HyperXLib.o" "{MPW}"Libraries:interface.o
  20.  
  21.     © Copyright 1989 by Apple Computer, Inc.
  22.  
  23.     Initial coding 1/89 by Harry R. Chesley.
  24.     Added empty OKChar processing 4/3/89, Harry R. Chesley.
  25. *)
  26.  
  27. {$R-}
  28.  
  29. {$S TCPRecvMsg }     { Segment name must be the same as the command name. }
  30.  
  31. unit DummyUnit;
  32.  
  33. interface
  34.  
  35. uses MemTypes, QuickDraw, OSIntf, ToolIntf, HyperXCmd;
  36.  
  37. procedure EntryPoint(paramPtr: XCmdPtr);
  38.     
  39. implementation
  40.  
  41. const
  42.  
  43. LINEFEED = 10;                { ASCII for line feed. }
  44. RETURN = 13;                { ASCII for carriage return. }
  45. CONTROLH = 8;                { ASCII for backspace. }
  46. TAB = 9;                        { ASCII for tab. }
  47. FORMFEED = 12;            { ASCII for form feed. }
  48. TABSTOPS = 8;            { Number of columns per tab stop. }
  49.  
  50. procedure TCPRecvMsg(paramPtr: XCmdPtr); forward;
  51.  
  52. procedure EntryPoint(paramPtr: XCmdPtr);
  53.  
  54.     begin
  55.         TCPRecvMsg(paramPtr);
  56.     end;
  57.  
  58. procedure TCPRecvMsg(paramPtr: XCmdPtr);
  59.  
  60.     type stateList =
  61.         (firstChar,lastErrorLinefeed,secondWord,endOfOKLine,endOfLine,firstPeriod,
  62.             secondPeriod,lastLinefeed);
  63.  
  64.     var str: Str255;
  65.         l: longInt;
  66.         i: integer;
  67.         waitForChars: longInt;        { Ticks to wait until for characters (compated to TickCount). }
  68.         resultHand: Handle;            { A handle to the result string. }
  69.         resultSize: longInt;            { The size of the result string (minus the zero termination tacked on last). }
  70.         limit: longInt;                    { Size limitation. }
  71.         okChar: SignedByte;            { Message is OK if first char is this. }
  72.         theChar: SignedByte;        { Input character. }
  73.         tabColumn: integer;            { Current column. }
  74.  
  75.     procedure Fail(errMsg: Str255); { set theResult and quit }
  76.         begin
  77.             paramPtr^.returnValue := PasToZero(paramPtr,errMsg);
  78.             exit(TCPRecvMsg);
  79.         end;
  80.  
  81.     {$I TCPUtil.inc}
  82.  
  83.     procedure disposAndFail(err: str255);
  84.         { Fail routine used after the result handle has been allocated. }
  85.  
  86.         begin
  87.             DisposHandle(resultHand);
  88.             Fail(err);
  89.         end;
  90.  
  91.     procedure putByte(b: SignedByte);
  92.         { Put the byte b after the output handle, increasing the handle's size in the process. }
  93.  
  94.         var p: Ptr;
  95.  
  96.         begin
  97.             if resultSize < limit then
  98.                 begin
  99.                     resultSize := resultSize+1;
  100.                     SetHandleSize(resultHand,resultSize);
  101.                     if MemError <> noErr then disposAndFail('§§§ SetHandleSize failed §§§');
  102.                     p := Ptr(ord4(resultHand^)+resultSize-1);
  103.                     p^ := b;
  104.                 end;
  105.         end;
  106.  
  107.     procedure putString(s: Str255);
  108.         { Put each byte in the string. }
  109.  
  110.         var i: integer;
  111.  
  112.         begin
  113.             for i := 1 to length(s) do
  114.                 putByte(SignedByte(s[i]));
  115.         end;
  116.  
  117.     function nextByte: SignedByte;
  118.         { Return the next byte in the buffer, reading more in if necessary. }
  119.     
  120.         var waitUntil: longInt;
  121.             readIn: longInt;
  122.     
  123.         begin
  124.             with Connection^ do
  125.                 begin
  126.                     if incomingSize = 0 then
  127.                         begin
  128.                             waitUntil := TickCount + waitForChars;
  129.                             while true do
  130.                                 begin
  131.                                     { Check the status. }
  132.                                     ZeroIOParms;
  133.                                     SyncControlBlock.csCode := TCPcsStatus;
  134.                                     if PBControl(@SyncControlBlock,false) <> noErr then
  135.                                         disposAndFail('§§§ TCP status failed §§§');
  136.                                     readIn := ControlWordAtOffset(60);
  137.                                     { If there's something to read, do so. }
  138.                                     if readIn > 0 then
  139.                                         begin
  140.                                             { Read only up to the buffer size. }
  141.                                             if readIn > INCOMINGBUFSIZE then readIn := INCOMINGBUFSIZE;
  142.                                             { Issue the read. }
  143.                                             ZeroIOParms;
  144.                                             SyncControlBlock.csCode := TCPcsRcv;
  145.                                             PutControlLongAtOffset(ord4(@inBuf),36);
  146.                                             PutControlWordAtOffset(readIn,40);
  147.                                             if PBControl(@SyncControlBlock,false) <> noErr then
  148.                                                 disposAndFail('§§§ TCP read failed §§§');
  149.                                             incomingSize := readIn;
  150.                                             incomingPtr := @inBuf;
  151.                                             leave;
  152.                                         end
  153.                                     { If not, check the timeout condition. }
  154.                                     else if TickCount > waitUntil then
  155.                                         begin
  156.                                             putByte(0);
  157.                                             paramPtr^.returnValue := resultHand;
  158.                                             exit(TCPRecvMsg);
  159.                                         end;
  160.                                 end;
  161.                         end;
  162.                     { Get the byte. }
  163.                     nextByte := incomingPtr^;
  164.                     incomingPtr := Ptr(ord4(incomingPtr)+1);
  165.                     incomingSize := incomingSize-1;
  166.                 end;
  167.         end;
  168.  
  169.     begin
  170.         if paramPtr^.paramCount <> 4 then Fail('§§§ parameter count is not 4 §§§');
  171.  
  172.         SetUpConnectionID;
  173.  
  174.         waitForChars := GetLongParm(2);                    { Second parameter is whether to wait. }
  175.         GetStrParm(3,str);                                        { Third parameter is OK char. }
  176.         if length(str) = 0 then okChar := 0
  177.         else okChar := SignedByte(str[1]);
  178.         limit := GetLongParm(4);                                { Fourth parameter is the size limit. }
  179.  
  180.         { Create the return handle. }
  181.         resultHand := NewHandle(0);
  182.         resultSize := 0;
  183.  
  184.         { Start in the first column. }
  185.         tabColumn := 0;
  186.  
  187.         { Get the first character. }
  188.         if okChar <> 0 then theChar := nextByte;
  189.         { Check if this is a good message or an error. }
  190.         if (theChar <> okChar) and (okChar <> 0) then
  191.             begin
  192.                 { If error, return the line, surounded by bullets. }
  193.                 putString('••• ');
  194.                 while theChar <> RETURN do
  195.                     begin
  196.                         putByte(theChar);
  197.                         theChar := nextByte;
  198.                     end;
  199.                 putString(' •••');
  200.                 { Skip the linefeed. }
  201.                 theChar := nextByte;
  202.             end
  203.         else
  204.             begin
  205.                 { Skip the first line. }
  206.                 if okChar <> 0 then repeat until nextByte = LINEFEED;
  207.  
  208.                 { Repeat for each line. }
  209.                 while true do
  210.                     begin
  211.                         { Check the first char for period. }
  212.                         theChar := nextByte;
  213.                         if theChar = ord('.') then
  214.                             begin
  215.                                 { Initial period. Might be end-of-message. Check the second char. }
  216.                                 theChar := nextByte;
  217.                                 if theChar = RETURN then
  218.                                     begin
  219.                                         { End-of-message. Skip the linefeed and return. }
  220.                                         theChar := nextByte;
  221.                                         leave;
  222.                                     end
  223.                                 { Otherwise, output the initial period. }
  224.                                 else putByte(ord('.'));
  225.                                 { Plus the next char if it wasn't a doubled initial period. }
  226.                                 if theChar <> ord('.') then putByte(theChar);
  227.                                 { Get the next char in the line. }
  228.                                 theChar := nextByte;
  229.                             end;
  230.                         { Do the rest of the line. }
  231.                         while theChar <> LINEFEED do
  232.                             begin
  233.                                 if theChar = TAB then
  234.                                     begin
  235.                                         { Space out to the tab stop. }
  236.                                         repeat
  237.                                             putByte(SignedByte(' '));
  238.                                             tabColumn := tabColumn+1;
  239.                                         until (tabColumn mod TABSTOPS) = 0;
  240.                                     end
  241.                                 else if theChar = CONTROLH then
  242.                                     begin
  243.                                         { Back up one, if there's anything to back up over. }
  244.                                         if (tabColumn > 0) and (resultSize > 0) then
  245.                                             begin
  246.                                                 resultSize := resultSize-1;
  247.                                                 tabColumn := tabColumn-1;
  248.                                             end;
  249.                                     end
  250.                                 else if theChar = FORMFEED then
  251.                                     begin
  252.                                         { Insert a page-break. }
  253.                                         for i := 1 to 20 do putByte(SignedByte('◊'));
  254.                                         for i := 1 to 24 do putByte(RETURN);
  255.                                     end
  256.                                 else if theChar <> LINEFEED then
  257.                                     begin
  258.                                         { Just put the character out straight, and adjust the tabbing. }
  259.                                         putByte(theChar);
  260.                                         if theChar = RETURN then tabColumn := 0
  261.                                         else tabColumn := tabColumn+1;
  262.                                     end;
  263.                                 theChar := nextByte;
  264.                             end;
  265.                     end;
  266.                 { Check if we overrun the allowed size. }
  267.                 if resultSize = limit then putString('••• message too big •••');
  268.             end;
  269.  
  270.         { Add in the zero termination for the string. }
  271.         putByte(0);
  272.  
  273.         { Return the handle. }
  274.         paramPtr^.returnValue := resultHand;
  275.     end;
  276.  
  277. end.
  278.